import axios from "axios";
import { formatProxyInfo, parseProxyUrl } from "../../../utils";
import { HttpsProxyAgent } from 'https-proxy-agent';
import { ProxyRequestExceptionError } from "../errors";

export class ProxyRequest {
  constructor(requestFactory, accountUser){
    this.requestFactory = requestFactory;
    this.accountUser = accountUser;
  }

  async request(options){
    const area = this.accountUser.area;
    
    if(area){
      const httpxProxyFormat = await this.getHttpProxyInfo();
      console.log('获取代理信息', 'ProxyRequest', httpxProxyFormat)
      options.httpsAgent = new HttpsProxyAgent(httpxProxyFormat);
    }

    const pRetry = (...args) => import('p-retry').then(({default: retry}) => retry(...args));

    return pRetry(async () => {
      return this.proxyRequest(options)
    }, {
      retries: 3,
      shouldRetry: (error) => error instanceof ProxyRequestExceptionError,
      onFailedAttempt: async (error) => {
        const { httpsAgent = null, ...logOptions } = options;

        console.log(`代理请求失败，剩余重试次数: ${error.retriesLeft}, 请求信息为: ${JSON.stringify(logOptions)}, 错误信息为: ${error.message}`);

        if(error instanceof ProxyRequestExceptionError){
          const httpxProxyFormat = await this.getHttpProxyInfo(true);
          console.log('重新获取代理信息', 'ProxyRequest', httpxProxyFormat)
          options.httpsAgent = new HttpsProxyAgent(httpxProxyFormat);
        }
      }
    });
  }

  async proxyRequest(options){
    let response

    console.log(`ProxyRequest:Options-----> ${JSON.stringify(options)}`)
    
    try {
      response = await axios(options)
    } catch (e){
      const errorMessage = e.message.toLowerCase();

      console.log(`ProxyRequest:Exception-----> ${errorMessage}`)
      
      if (
        errorMessage.includes('http_proxy') || 
        errorMessage.includes('ssl handshake failed') ||
        errorMessage.includes('not match certificate') ||
        errorMessage.includes('服务器打瞌睡') ||
        errorMessage.includes('connection reset by peer') ||
        errorMessage.includes('socket hang up') ||
        errorMessage.includes('getaddrinfo') ||
        errorMessage.includes('timeout') ||
        errorMessage.includes('timed out') ||
        (errorMessage.includes('request failed with status code') && (! errorMessage.includes('403'))) ||
        errorMessage.includes('network socket disconnected') ||
        errorMessage.includes('connect econreset') || 
        errorMessage.includes('connect etimedout') || 
        errorMessage.includes('read econreset') || 
        errorMessage.includes('read etimedout')
      ) {
        throw new ProxyRequestExceptionError(e.message);
      }
      
      throw e;
    }

    return response
  }

  async getHttpProxyInfo(refresh = false){
    const result = await this.getProxyInfo(refresh);

    const proxy = `${result.protocol}${result.user}:${result.password}@${result.ip}:${result.port}`;
    
    return proxy;
    // const ipProxyInfo = parseProxyUrl(proxy);
    // const [_, httpProxyFormat] = formatProxyInfo(ipProxyInfo);

    // return httpProxyFormat
  }

  async getProxyInfo(refresh = false){
    const { data: { result } } = await this.requestFactory.request({
      url: '/work_ai/platform/account/proxy',
      params: {
        account_id: this.accountUser.id,
        refresh: refresh ? 1 : 0,
        validate: 1
      }
    })
    
    return result
  }
}